home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 March / EnigmA AMIGA RUN 05 (1996)(G.R. Edizioni)(IT)[!][issue 1996-03][Skylink CD IV].iso / earcd / program / ixemlsrc.lha / ixemul / static / localtime.c < prev    next >
C/C++ Source or Header  |  1996-01-11  |  39KB  |  1,607 lines

  1. /*
  2. ** Leap second handling from Bradley White (bww@k.gp.cs.cmu.edu).
  3. ** POSIX-style TZ environment variable handling from Guy Harris
  4. ** (guy@auspex.com).
  5. */
  6.  
  7. /*LINTLIBRARY*/
  8.  
  9. #include "private.h"
  10. #include "tzfile.h"
  11. #include "fcntl.h"
  12.  
  13. /*
  14. ** SunOS 4.1.1 headers lack O_BINARY.
  15. */
  16.  
  17. #ifdef O_BINARY
  18. #define OPEN_MODE    (O_RDONLY | O_BINARY)
  19. #endif /* defined O_BINARY */
  20. #ifndef O_BINARY
  21. #define OPEN_MODE    O_RDONLY
  22. #endif /* !defined O_BINARY */
  23.  
  24. #ifndef WILDABBR
  25. /*
  26. ** Someone might make incorrect use of a time zone abbreviation:
  27. **    1.    They might reference tzname[0] before calling tzset (explicitly
  28. **        or implicitly).
  29. **    2.    They might reference tzname[1] before calling tzset (explicitly
  30. **        or implicitly).
  31. **    3.    They might reference tzname[1] after setting to a time zone
  32. **        in which Daylight Saving Time is never observed.
  33. **    4.    They might reference tzname[0] after setting to a time zone
  34. **        in which Standard Time is never observed.
  35. **    5.    They might reference tm.TM_ZONE after calling offtime.
  36. ** What's best to do in the above cases is open to debate;
  37. ** for now, we just set things up so that in any of the five cases
  38. ** WILDABBR is used.  Another possibility:  initialize tzname[0] to the
  39. ** string "tzname[0] used before set", and similarly for the other cases.
  40. ** And another:  initialize tzname[0] to "ERA", with an explanation in the
  41. ** manual page of what this "time zone abbreviation" means (doing this so
  42. ** that tzname[0] has the "normal" length of three characters).
  43. */
  44. #define WILDABBR    "   "
  45. #endif /* !defined WILDABBR */
  46.  
  47. static char        wildabbr[] = "WILDABBR";
  48.  
  49. static const char    gmt[] = "GMT";
  50.  
  51. struct ttinfo {                /* time type information */
  52.     long        tt_gmtoff;    /* GMT offset in seconds */
  53.     int        tt_isdst;    /* used to set tm_isdst */
  54.     int        tt_abbrind;    /* abbreviation list index */
  55.     int        tt_ttisstd;    /* TRUE if transition is std time */
  56.     int        tt_ttisgmt;    /* TRUE if transition is GMT */
  57. };
  58.  
  59. struct lsinfo {                /* leap second information */
  60.     time_t        ls_trans;    /* transition time */
  61.     long        ls_corr;    /* correction to apply */
  62. };
  63.  
  64. #define BIGGEST(a, b)    (((a) > (b)) ? (a) : (b))
  65.  
  66. #ifdef TZNAME_MAX
  67. #define MY_TZNAME_MAX    TZNAME_MAX
  68. #endif /* defined TZNAME_MAX */
  69. #ifndef TZNAME_MAX
  70. #define MY_TZNAME_MAX    255
  71. #endif /* !defined TZNAME_MAX */
  72.  
  73. struct state {
  74.     int        leapcnt;
  75.     int        timecnt;
  76.     int        typecnt;
  77.     int        charcnt;
  78.     time_t        ats[TZ_MAX_TIMES];
  79.     unsigned char    types[TZ_MAX_TIMES];
  80.     struct ttinfo    ttis[TZ_MAX_TYPES];
  81.     char        chars[BIGGEST(BIGGEST(TZ_MAX_CHARS + 1, sizeof gmt),
  82.                 (2 * (MY_TZNAME_MAX + 1)))];
  83.     struct lsinfo    lsis[TZ_MAX_LEAPS];
  84. };
  85.  
  86. struct rule {
  87.     int        r_type;        /* type of rule--see below */
  88.     int        r_day;        /* day number of rule */
  89.     int        r_week;        /* week number of rule */
  90.     int        r_mon;        /* month number of rule */
  91.     long        r_time;        /* transition time of rule */
  92. };
  93.  
  94. #define JULIAN_DAY        0    /* Jn - Julian day */
  95. #define DAY_OF_YEAR        1    /* n - day of year */
  96. #define MONTH_NTH_DAY_OF_WEEK    2    /* Mm.n.d - month, week, day of week */
  97.  
  98. /*
  99. ** Prototypes for static functions.
  100. */
  101.  
  102. static long        detzcode P((const char * codep));
  103. static const char *    getzname P((const char * strp));
  104. static const char *    getnum P((const char * strp, int * nump, int min,
  105.                 int max));
  106. static const char *    getsecs P((const char * strp, long * secsp));
  107. static const char *    getoffset P((const char * strp, long * offsetp));
  108. static const char *    getrule P((const char * strp, struct rule * rulep));
  109. static void        gmtload P((struct state * sp));
  110. static void        gmtsub P((const time_t * timep, long offset,
  111.                 struct tm * tmp));
  112. static void        localsub P((const time_t * timep, long offset,
  113.                 struct tm * tmp));
  114. static int        increment_overflow P((int * number, int delta));
  115. static int        normalize_overflow P((int * tensptr, int * unitsptr,
  116.                 int base));
  117. static void        settzname P((void));
  118. static time_t        time1 P((struct tm * tmp,
  119.                 void(*funcp) P((const time_t *,
  120.                 long, struct tm *)),
  121.                 long offset));
  122. static time_t        time2 P((struct tm *tmp,
  123.                 void(*funcp) P((const time_t *,
  124.                 long, struct tm*)),
  125.                 long offset, int * okayp));
  126. static void        timesub P((const time_t * timep, long offset,
  127.                 const struct state * sp, struct tm * tmp));
  128. static int        tmcomp P((const struct tm * atmp,
  129.                 const struct tm * btmp));
  130. static time_t        transtime P((time_t janfirst, int year,
  131.                 const struct rule * rulep, long offset));
  132. static int        tzload P((const char * name, struct state * sp));
  133. static int        tzparse P((const char * name, struct state * sp,
  134.                 int lastditch));
  135.  
  136. #ifdef ALL_STATE
  137. static struct state *    lclptr;
  138. static struct state *    gmtptr;
  139. #endif /* defined ALL_STATE */
  140.  
  141. #ifndef ALL_STATE
  142. static struct state    lclmem;
  143. static struct state    gmtmem;
  144. #define lclptr        (&lclmem)
  145. #define gmtptr        (&gmtmem)
  146. #endif /* State Farm */
  147.  
  148. #ifndef TZ_STRLEN_MAX
  149. #define TZ_STRLEN_MAX 255
  150. #endif /* !defined TZ_STRLEN_MAX */
  151.  
  152. static char        lcl_TZname[TZ_STRLEN_MAX + 1];
  153. static int        lcl_is_set;
  154. static int        gmt_is_set;
  155.  
  156. char *            tzname[2] = {
  157.     wildabbr,
  158.     wildabbr
  159. };
  160.  
  161. /*
  162. ** Section 4.12.3 of X3.159-1989 requires that
  163. **    Except for the strftime function, these functions [asctime,
  164. **    ctime, gmtime, localtime] return values in one of two static
  165. **    objects: a broken-down time structure and an array of char.
  166. ** Thanks to Paul Eggert (eggert@twinsun.com) for noting this.
  167. */
  168.  
  169. static struct tm    tm;
  170.  
  171. #ifdef USG_COMPAT
  172. time_t            timezone = 0;
  173. int            daylight = 0;
  174. #endif /* defined USG_COMPAT */
  175.  
  176. #ifdef ALTZONE
  177. time_t            altzone = 0;
  178. #endif /* defined ALTZONE */
  179.  
  180. static long
  181. detzcode(codep)
  182. const char * const    codep;
  183. {
  184.     register long    result;
  185.     register int    i;
  186.  
  187.     result = (codep[0] & 0x80) ? ~0L : 0L;
  188.     for (i = 0; i < 4; ++i)
  189.         result = (result << 8) | (codep[i] & 0xff);
  190.     return result;
  191. }
  192.  
  193. static void
  194. settzname P((void))
  195. {
  196.     register struct state * const    sp = lclptr;
  197.     register int            i;
  198.  
  199.     tzname[0] = wildabbr;
  200.     tzname[1] = wildabbr;
  201. #ifdef USG_COMPAT
  202.     daylight = 0;
  203.     timezone = 0;
  204. #endif /* defined USG_COMPAT */
  205. #ifdef ALTZONE
  206.     altzone = 0;
  207. #endif /* defined ALTZONE */
  208. #ifdef ALL_STATE
  209.     if (sp == NULL) {
  210.         tzname[0] = tzname[1] = gmt;
  211.         return;
  212.     }
  213. #endif /* defined ALL_STATE */
  214.     for (i = 0; i < sp->typecnt; ++i) {
  215.         register const struct ttinfo * const    ttisp = &sp->ttis[i];
  216.  
  217.         tzname[ttisp->tt_isdst] =
  218.             &sp->chars[ttisp->tt_abbrind];
  219. #ifdef USG_COMPAT
  220.         if (ttisp->tt_isdst)
  221.             daylight = 1;
  222.         if (i == 0 || !ttisp->tt_isdst)
  223.             timezone = -(ttisp->tt_gmtoff);
  224. #endif /* defined USG_COMPAT */
  225. #ifdef ALTZONE
  226.         if (i == 0 || ttisp->tt_isdst)
  227.             altzone = -(ttisp->tt_gmtoff);
  228. #endif /* defined ALTZONE */
  229.     }
  230.     /*
  231.     ** And to get the latest zone names into tzname. . .
  232.     */
  233.     for (i = 0; i < sp->timecnt; ++i) {
  234.         register const struct ttinfo * const    ttisp =
  235.                             &sp->ttis[
  236.                                 sp->types[i]];
  237.  
  238.         tzname[ttisp->tt_isdst] =
  239.             &sp->chars[ttisp->tt_abbrind];
  240.     }
  241. }
  242.  
  243. static int
  244. tzload(name, sp)
  245. register const char *        name;
  246. register struct state * const    sp;
  247. {
  248.     register const char *    p;
  249.     register int        i;
  250.     register int        fid;
  251.  
  252.     if (name == NULL && (name = TZDEFAULT) == NULL)
  253.         return -1;
  254.     {
  255.         register int    doaccess;
  256.         /*
  257.         ** Section 4.9.1 of the C standard says that
  258.         ** "FILENAME_MAX expands to an integral constant expression
  259.         ** that is the sie needed for an array of char large enough
  260.         ** to hold the longest file name string that the implementation
  261.         ** guarantees can be opened."
  262.         */
  263.         char        fullname[FILENAME_MAX + 1];
  264.  
  265.         if (name[0] == ':')
  266.             ++name;
  267.         doaccess = name[0] == '/';
  268.         if (!doaccess) {
  269.             if ((p = TZDIR) == NULL)
  270.                 return -1;
  271.             if ((strlen(p) + strlen(name) + 1) >= sizeof fullname)
  272.                 return -1;
  273.             (void) strcpy(fullname, p);
  274.             (void) strcat(fullname, "/");
  275.             (void) strcat(fullname, name);
  276.             /*
  277.             ** Set doaccess if '.' (as in "../") shows up in name.
  278.             */
  279.             if (strchr(name, '.') != NULL)
  280.                 doaccess = TRUE;
  281.             name = fullname;
  282.         }
  283.         if (doaccess && access(name, R_OK) != 0)
  284.             return -1;
  285.         if ((fid = open(name, OPEN_MODE)) == -1)
  286.             return -1;
  287.     }
  288.     {
  289.         struct tzhead *    tzhp;
  290.         char        buf[sizeof *sp + sizeof *tzhp];
  291.         int        ttisstdcnt;
  292.         int        ttisgmtcnt;
  293.  
  294.         i = read(fid, buf, sizeof buf);
  295.         if (close(fid) != 0)
  296.             return -1;
  297.         p = buf;
  298.         p += sizeof tzhp->tzh_reserved;
  299.         ttisstdcnt = (int) detzcode(p);
  300.         p += 4;
  301.         ttisgmtcnt = (int) detzcode(p);
  302.         p += 4;
  303.         sp->leapcnt = (int) detzcode(p);
  304.         p += 4;
  305.         sp->timecnt = (int) detzcode(p);
  306.         p += 4;
  307.         sp->typecnt = (int) detzcode(p);
  308.         p += 4;
  309.         sp->charcnt = (int) detzcode(p);
  310.         p += 4;
  311.         if (sp->leapcnt < 0 || sp->leapcnt > TZ_MAX_LEAPS ||
  312.             sp->typecnt <= 0 || sp->typecnt > TZ_MAX_TYPES ||
  313.             sp->timecnt < 0 || sp->timecnt > TZ_MAX_TIMES ||
  314.             sp->charcnt < 0 || sp->charcnt > TZ_MAX_CHARS ||
  315.             (ttisstdcnt != sp->typecnt && ttisstdcnt != 0) ||
  316.             (ttisgmtcnt != sp->typecnt && ttisgmtcnt != 0))
  317.                 return -1;
  318.         if (i - (p - buf) < sp->timecnt * 4 +    /* ats */
  319.             sp->timecnt +            /* types */
  320.             sp->typecnt * (4 + 2) +        /* ttinfos */
  321.             sp->charcnt +            /* chars */
  322.             sp->leapcnt * (4 + 4) +        /* lsinfos */
  323.             ttisstdcnt +            /* ttisstds */
  324.             ttisgmtcnt)            /* ttisgmts */
  325.                 return -1;
  326.         for (i = 0; i < sp->timecnt; ++i) {
  327.             sp->ats[i] = detzcode(p);
  328.             p += 4;
  329.         }
  330.         for (i = 0; i < sp->timecnt; ++i) {
  331.             sp->types[i] = (unsigned char) *p++;
  332.             if (sp->types[i] >= sp->typecnt)
  333.                 return -1;
  334.         }
  335.         for (i = 0; i < sp->typecnt; ++i) {
  336.             register struct ttinfo *    ttisp;
  337.  
  338.             ttisp = &sp->ttis[i];
  339.             ttisp->tt_gmtoff = detzcode(p);
  340.             p += 4;
  341.             ttisp->tt_isdst = (unsigned char) *p++;
  342.             if (ttisp->tt_isdst != 0 && ttisp->tt_isdst != 1)
  343.                 return -1;
  344.             ttisp->tt_abbrind = (unsigned char) *p++;
  345.             if (ttisp->tt_abbrind < 0 ||
  346.                 ttisp->tt_abbrind > sp->charcnt)
  347.                     return -1;
  348.         }
  349.         for (i = 0; i < sp->charcnt; ++i)
  350.             sp->chars[i] = *p++;
  351.         sp->chars[i] = '\0';    /* ensure '\0' at end */
  352.         for (i = 0; i < sp->leapcnt; ++i) {
  353.             register struct lsinfo *    lsisp;
  354.  
  355.             lsisp = &sp->lsis[i];
  356.             lsisp->ls_trans = detzcode(p);
  357.             p += 4;
  358.             lsisp->ls_corr = detzcode(p);
  359.             p += 4;
  360.         }
  361.         for (i = 0; i < sp->typecnt; ++i) {
  362.             register struct ttinfo *    ttisp;
  363.  
  364.             ttisp = &sp->ttis[i];
  365.             if (ttisstdcnt == 0)
  366.                 ttisp->tt_ttisstd = FALSE;
  367.             else {
  368.                 ttisp->tt_ttisstd = *p++;
  369.                 if (ttisp->tt_ttisstd != TRUE &&
  370.                     ttisp->tt_ttisstd != FALSE)
  371.                         return -1;
  372.             }
  373.         }
  374.         for (i = 0; i < sp->typecnt; ++i) {
  375.             register struct ttinfo *    ttisp;
  376.  
  377.             ttisp = &sp->ttis[i];
  378.             if (ttisgmtcnt == 0)
  379.                 ttisp->tt_ttisgmt = FALSE;
  380.             else {
  381.                 ttisp->tt_ttisgmt = *p++;
  382.                 if (ttisp->tt_ttisgmt != TRUE &&
  383.                     ttisp->tt_ttisgmt != FALSE)
  384.                         return -1;
  385.             }
  386.         }
  387.     }
  388.     return 0;
  389. }
  390.  
  391. static const int    mon_lengths[2][MONSPERYEAR] = {
  392.     { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
  393.     { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
  394. };
  395.  
  396. static const int    year_lengths[2] = {
  397.     DAYSPERNYEAR, DAYSPERLYEAR
  398. };
  399.  
  400. /*
  401. ** Given a pointer into a time zone string, scan until a character that is not
  402. ** a valid character in a zone name is found.  Return a pointer to that
  403. ** character.
  404. */
  405.  
  406. static const char *
  407. getzname(strp)
  408. register const char *    strp;
  409. {
  410.     register char    c;
  411.  
  412.     while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' &&
  413.         c != '+')
  414.             ++strp;
  415.     return strp;
  416. }
  417.  
  418. /*
  419. ** Given a pointer into a time zone string, extract a number from that string.
  420. ** Check that the number is within a specified range; if it is not, return
  421. ** NULL.
  422. ** Otherwise, return a pointer to the first character not part of the number.
  423. */
  424.  
  425. static const char *
  426. getnum(strp, nump, min, max)
  427. register const char *    strp;
  428. int * const        nump;
  429. const int        min;
  430. const int        max;
  431. {
  432.     register char    c;
  433.     register int    num;
  434.  
  435.     if (strp == NULL || !is_digit(c = *strp))
  436.         return NULL;
  437.     num = 0;
  438.     do {
  439.         num = num * 10 + (c - '0');
  440.         if (num > max)
  441.             return NULL;    /* illegal value */
  442.         c = *++strp;
  443.     } while (is_digit(c));
  444.     if (num < min)
  445.         return NULL;        /* illegal value */
  446.     *nump = num;
  447.     return strp;
  448. }
  449.  
  450. /*
  451. ** Given a pointer into a time zone string, extract a number of seconds,
  452. ** in hh[:mm[:ss]] form, from the string.
  453. ** If any error occurs, return NULL.
  454. ** Otherwise, return a pointer to the first character not part of the number
  455. ** of seconds.
  456. */
  457.  
  458. static const char *
  459. getsecs(strp, secsp)
  460. register const char *    strp;
  461. long * const        secsp;
  462. {
  463.     int    num;
  464.  
  465.     /*
  466.     ** `HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
  467.     ** "M10.4.6/26", which does not conform to Posix,
  468.     ** but which specifies the equivalent of
  469.     ** ``02:00 on the first Sunday on or after 23 Oct''.
  470.     */
  471.     strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
  472.     if (strp == NULL)
  473.         return NULL;
  474.     *secsp = num * (long) SECSPERHOUR;
  475.     if (*strp == ':') {
  476.         ++strp;
  477.         strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
  478.         if (strp == NULL)
  479.             return NULL;
  480.         *secsp += num * SECSPERMIN;
  481.         if (*strp == ':') {
  482.             ++strp;
  483.             /* `SECSPERMIN' allows for leap seconds.  */
  484.             strp = getnum(strp, &num, 0, SECSPERMIN);
  485.             if (strp == NULL)
  486.                 return NULL;
  487.             *secsp += num;
  488.         }
  489.     }
  490.     return strp;
  491. }
  492.  
  493. /*
  494. ** Given a pointer into a time zone string, extract an offset, in
  495. ** [+-]hh[:mm[:ss]] form, from the string.
  496. ** If any error occurs, return NULL.
  497. ** Otherwise, return a pointer to the first character not part of the time.
  498. */
  499.  
  500. static const char *
  501. getoffset(strp, offsetp)
  502. register const char *    strp;
  503. long * const        offsetp;
  504. {
  505.     register int    neg = 0;
  506.  
  507.     if (*strp == '-') {
  508.         neg = 1;
  509.         ++strp;
  510.     } else if (*strp == '+')
  511.         ++strp;
  512.     strp = getsecs(strp, offsetp);
  513.     if (strp == NULL)
  514.         return NULL;        /* illegal time */
  515.     if (neg)
  516.         *offsetp = -*offsetp;
  517.     return strp;
  518. }
  519.  
  520. /*
  521. ** Given a pointer into a time zone string, extract a rule in the form
  522. ** date[/time].  See POSIX section 8 for the format of "date" and "time".
  523. ** If a valid rule is not found, return NULL.
  524. ** Otherwise, return a pointer to the first character not part of the rule.
  525. */
  526.  
  527. static const char *
  528. getrule(strp, rulep)
  529. const char *            strp;
  530. register struct rule * const    rulep;
  531. {
  532.     if (*strp == 'J') {
  533.         /*
  534.         ** Julian day.
  535.         */
  536.         rulep->r_type = JULIAN_DAY;
  537.         ++strp;
  538.         strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
  539.     } else if (*strp == 'M') {
  540.         /*
  541.         ** Month, week, day.
  542.         */
  543.         rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
  544.         ++strp;
  545.         strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
  546.         if (strp == NULL)
  547.             return NULL;
  548.         if (*strp++ != '.')
  549.             return NULL;
  550.         strp = getnum(strp, &rulep->r_week, 1, 5);
  551.         if (strp == NULL)
  552.             return NULL;
  553.         if (*strp++ != '.')
  554.             return NULL;
  555.         strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
  556.     } else if (is_digit(*strp)) {
  557.         /*
  558.         ** Day of year.
  559.         */
  560.         rulep->r_type = DAY_OF_YEAR;
  561.         strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
  562.     } else    return NULL;        /* invalid format */
  563.     if (strp == NULL)
  564.         return NULL;
  565.     if (*strp == '/') {
  566.         /*
  567.         ** Time specified.
  568.         */
  569.         ++strp;
  570.         strp = getsecs(strp, &rulep->r_time);
  571.     } else    rulep->r_time = 2 * SECSPERHOUR;    /* default = 2:00:00 */
  572.     return strp;
  573. }
  574.  
  575. /*
  576. ** Given the Epoch-relative time of January 1, 00:00:00 GMT, in a year, the
  577. ** year, a rule, and the offset from GMT at the time that rule takes effect,
  578. ** calculate the Epoch-relative time that rule takes effect.
  579. */
  580.  
  581. static time_t
  582. transtime(janfirst, year, rulep, offset)
  583. const time_t                janfirst;
  584. const int                year;
  585. register const struct rule * const    rulep;
  586. const long                offset;
  587. {
  588.     register int    leapyear;
  589.     register time_t    value;
  590.     register int    i;
  591.     int        d, m1, yy0, yy1, yy2, dow;
  592.  
  593.     INITIALIZE(value);
  594.     leapyear = isleap(year);
  595.     switch (rulep->r_type) {
  596.  
  597.     case JULIAN_DAY:
  598.         /*
  599.         ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
  600.         ** years.
  601.         ** In non-leap years, or if the day number is 59 or less, just
  602.         ** add SECSPERDAY times the day number-1 to the time of
  603.         ** January 1, midnight, to get the day.
  604.         */
  605.         value = janfirst + (rulep->r_day - 1) * SECSPERDAY;
  606.         if (leapyear && rulep->r_day >= 60)
  607.             value += SECSPERDAY;
  608.         break;
  609.  
  610.     case DAY_OF_YEAR:
  611.         /*
  612.         ** n - day of year.
  613.         ** Just add SECSPERDAY times the day number to the time of
  614.         ** January 1, midnight, to get the day.
  615.         */
  616.         value = janfirst + rulep->r_day * SECSPERDAY;
  617.         break;
  618.  
  619.     case MONTH_NTH_DAY_OF_WEEK:
  620.         /*
  621.         ** Mm.n.d - nth "dth day" of month m.
  622.         */
  623.         value = janfirst;
  624.         for (i = 0; i < rulep->r_mon - 1; ++i)
  625.             value += mon_lengths[leapyear][i] * SECSPERDAY;
  626.  
  627.         /*
  628.         ** Use Zeller's Congruence to get day-of-week of first day of
  629.         ** month.
  630.         */
  631.         m1 = (rulep->r_mon + 9) % 12 + 1;
  632.         yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
  633.         yy1 = yy0 / 100;
  634.         yy2 = yy0 % 100;
  635.         dow = ((26 * m1 - 2) / 10 +
  636.             1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
  637.         if (dow < 0)
  638.             dow += DAYSPERWEEK;
  639.  
  640.         /*
  641.         ** "dow" is the day-of-week of the first day of the month.  Get
  642.         ** the day-of-month (zero-origin) of the first "dow" day of the
  643.         ** month.
  644.         */
  645.         d = rulep->r_day - dow;
  646.         if (d < 0)
  647.             d += DAYSPERWEEK;
  648.         for (i = 1; i < rulep->r_week; ++i) {
  649.             if (d + DAYSPERWEEK >=
  650.                 mon_lengths[leapyear][rulep->r_mon - 1])
  651.                     break;
  652.             d += DAYSPERWEEK;
  653.         }
  654.  
  655.         /*
  656.         ** "d" is the day-of-month (zero-origin) of the day we want.
  657.         */
  658.         value += d * SECSPERDAY;
  659.         break;
  660.     }
  661.  
  662.     /*
  663.     ** "value" is the Epoch-relative time of 00:00:00 GMT on the day in
  664.     ** question.  To get the Epoch-relative time of the specified local
  665.     ** time on that day, add the transition time and the current offset
  666.     ** from GMT.
  667.     */
  668.     return value + rulep->r_time + offset;
  669. }
  670.  
  671. /*
  672. ** Given a POSIX section 8-style TZ string, fill in the rule tables as
  673. ** appropriate.
  674. */
  675.  
  676. static int
  677. tzparse(name, sp, lastditch)
  678. const char *            name;
  679. register struct state * const    sp;
  680. const int            lastditch;
  681. {
  682.     const char *            stdname;
  683.     const char *            dstname;
  684.     size_t                stdlen;
  685.     size_t                dstlen;
  686.     long                stdoffset;
  687.     long                dstoffset;
  688.     register time_t *        atp;
  689.     register unsigned char *    typep;
  690.     register char *            cp;
  691.     register int            load_result;
  692.  
  693.     INITIALIZE(dstname);
  694.     stdname = name;
  695.     if (lastditch) {
  696.         stdlen = strlen(name);    /* length of standard zone name */
  697.         name += stdlen;
  698.         if (stdlen >= sizeof sp->chars)
  699.             stdlen = (sizeof sp->chars) - 1;
  700.     } else {
  701.         name = getzname(name);
  702.         stdlen = name - stdname;
  703.         if (stdlen < 3)
  704.             return -1;
  705.     }
  706.     if (*name == '\0')
  707.         return -1;    /* was "stdoffset = 0;" */
  708.     else {
  709.         name = getoffset(name, &stdoffset);
  710.         if (name == NULL)
  711.             return -1;
  712.     }
  713.     load_result = tzload(TZDEFRULES, sp);
  714.     if (load_result != 0)
  715.         sp->leapcnt = 0;        /* so, we're off a little */
  716.     if (*name != '\0') {
  717.         dstname = name;
  718.         name = getzname(name);
  719.         dstlen = name - dstname;    /* length of DST zone name */
  720.         if (dstlen < 3)
  721.             return -1;
  722.         if (*name != '\0' && *name != ',' && *name != ';') {
  723.             name = getoffset(name, &dstoffset);
  724.             if (name == NULL)
  725.                 return -1;
  726.         } else    dstoffset = stdoffset - SECSPERHOUR;
  727.         if (*name == ',' || *name == ';') {
  728.             struct rule    start;
  729.             struct rule    end;
  730.             register int    year;
  731.             register time_t    janfirst;
  732.             time_t        starttime;
  733.             time_t        endtime;
  734.  
  735.             ++name;
  736.             if ((name = getrule(name, &start)) == NULL)
  737.                 return -1;
  738.             if (*name++ != ',')
  739.                 return -1;
  740.             if ((name = getrule(name, &end)) == NULL)
  741.                 return -1;
  742.             if (*name != '\0')
  743.                 return -1;
  744.             sp->typecnt = 2;    /* standard time and DST */
  745.             /*
  746.             ** Two transitions per year, from EPOCH_YEAR to 2037.
  747.             */
  748.             sp->timecnt = 2 * (2037 - EPOCH_YEAR + 1);
  749.             if (sp->timecnt > TZ_MAX_TIMES)
  750.                 return -1;
  751.             sp->ttis[0].tt_gmtoff = -dstoffset;
  752.             sp->ttis[0].tt_isdst = 1;
  753.             sp->ttis[0].tt_abbrind = stdlen + 1;
  754.             sp->ttis[1].tt_gmtoff = -stdoffset;
  755.             sp->ttis[1].tt_isdst = 0;
  756.             sp->ttis[1].tt_abbrind = 0;
  757.             atp = sp->ats;
  758.             typep = sp->types;
  759.             janfirst = 0;
  760.             for (year = EPOCH_YEAR; year <= 2037; ++year) {
  761.                 starttime = transtime(janfirst, year, &start,
  762.                     stdoffset);
  763.                 endtime = transtime(janfirst, year, &end,
  764.                     dstoffset);
  765.                 if (starttime > endtime) {
  766.                     *atp++ = endtime;
  767.                     *typep++ = 1;    /* DST ends */
  768.                     *atp++ = starttime;
  769.                     *typep++ = 0;    /* DST begins */
  770.                 } else {
  771.                     *atp++ = starttime;
  772.                     *typep++ = 0;    /* DST begins */
  773.                     *atp++ = endtime;
  774.                     *typep++ = 1;    /* DST ends */
  775.                 }
  776.                 janfirst += year_lengths[isleap(year)] *
  777.                     SECSPERDAY;
  778.             }
  779.         } else {
  780.             register long    theirstdoffset;
  781.             register long    theirdstoffset;
  782.             register long    theiroffset;
  783.             register int    isdst;
  784.             register int    i;
  785.             register int    j;
  786.  
  787.             if (*name != '\0')
  788.                 return -1;
  789.             if (load_result != 0)
  790.                 return -1;
  791.             /*
  792.             ** Initial values of theirstdoffset and theirdstoffset.
  793.             */
  794.             theirstdoffset = 0;
  795.             for (i = 0; i < sp->timecnt; ++i) {
  796.                 j = sp->types[i];
  797.                 if (!sp->ttis[j].tt_isdst) {
  798.                     theirstdoffset =
  799.                         -sp->ttis[j].tt_gmtoff;
  800.                     break;
  801.                 }
  802.             }
  803.             theirdstoffset = 0;
  804.             for (i = 0; i < sp->timecnt; ++i) {
  805.                 j = sp->types[i];
  806.                 if (sp->ttis[j].tt_isdst) {
  807.                     theirdstoffset =
  808.                         -sp->ttis[j].tt_gmtoff;
  809.                     break;
  810.                 }
  811.             }
  812.             /*
  813.             ** Initially we're assumed to be in standard time.
  814.             */
  815.             isdst = FALSE;
  816.             theiroffset = theirstdoffset;
  817.             /*
  818.             ** Now juggle transition times and types
  819.             ** tracking offsets as you do.
  820.             */
  821.             for (i = 0; i < sp->timecnt; ++i) {
  822.                 j = sp->types[i];
  823.                 sp->types[i] = sp->ttis[j].tt_isdst;
  824.                 if (sp->ttis[j].tt_ttisgmt) {
  825.                     /* No adjustment to transition time */
  826.                 } else {
  827.                     /*
  828.                     ** If summer time is in effect, and the
  829.                     ** transition time was not specified as
  830.                     ** standard time, add the summer time
  831.                     ** offset to the transition time;
  832.                     ** otherwise, add the standard time
  833.                     ** offset to the transition time.
  834.                     */
  835.                     /*
  836.                     ** Transitions from DST to DDST
  837.                     ** will effectively disappear since
  838.                     ** POSIX provides for only one DST
  839.                     ** offset.
  840.                     */
  841.                     if (isdst && !sp->ttis[j].tt_ttisstd) {
  842.                         sp->ats[i] += dstoffset -
  843.                             theirdstoffset;
  844.                     } else {
  845.                         sp->ats[i] += stdoffset -
  846.                             theirstdoffset;
  847.                     }
  848.                 }
  849.                 theiroffset = -sp->ttis[j].tt_gmtoff;
  850.                 if (sp->ttis[j].tt_isdst)
  851.                     theirdstoffset = theiroffset;
  852.                 else    theirstdoffset = theiroffset;
  853.             }
  854.             /*
  855.             ** Finally, fill in ttis.
  856.             ** ttisstd and ttisgmt need not be handled.
  857.             */
  858.             sp->ttis[0].tt_gmtoff = -stdoffset;
  859.             sp->ttis[0].tt_isdst = FALSE;
  860.             sp->ttis[0].tt_abbrind = 0;
  861.             sp->ttis[1].tt_gmtoff = -dstoffset;
  862.             sp->ttis[1].tt_isdst = TRUE;
  863.             sp->ttis[1].tt_abbrind = stdlen + 1;
  864.         }
  865.     } else {
  866.         dstlen = 0;
  867.         sp->typecnt = 1;        /* only standard time */
  868.         sp->timecnt = 0;
  869.         sp->ttis[0].tt_gmtoff = -stdoffset;
  870.         sp->ttis[0].tt_isdst = 0;
  871.         sp->ttis[0].tt_abbrind = 0;
  872.     }
  873.     sp->charcnt = stdlen + 1;
  874.     if (dstlen != 0)
  875.         sp->charcnt += dstlen + 1;
  876.     if (sp->charcnt > sizeof sp->chars)
  877.         return -1;
  878.     cp = sp->chars;
  879.     (void) strncpy(cp, stdname, stdlen);
  880.     cp += stdlen;
  881.     *cp++ = '\0';
  882.     if (dstlen != 0) {
  883.         (void) strncpy(cp, dstname, dstlen);
  884.         *(cp + dstlen) = '\0';
  885.     }
  886.     return 0;
  887. }
  888.  
  889. static void
  890. gmtload(sp)
  891. struct state * const    sp;
  892. {
  893.     if (tzload(gmt, sp) != 0)
  894.         (void) tzparse(gmt, sp, TRUE);
  895. }
  896.  
  897. #if !defined(STD_INSPIRED) && !defined(amigados)
  898. /*
  899. ** A non-static declaration of tzsetwall in a system header file
  900. ** may cause a warning about this upcoming static declaration...
  901. */
  902. static
  903. #endif /* !defined STD_INSPIRED */
  904. void
  905. tzsetwall P((void))
  906. {
  907.     if (lcl_is_set < 0)
  908.         return;
  909.     lcl_is_set = -1;
  910.  
  911. #ifdef ALL_STATE
  912.     if (lclptr == NULL) {
  913.         lclptr = (struct state *) malloc(sizeof *lclptr);
  914.         if (lclptr == NULL) {
  915.             settzname();    /* all we can do */
  916.             return;
  917.         }
  918.     }
  919. #endif /* defined ALL_STATE */
  920.     if (tzload((char *) NULL, lclptr) != 0)
  921.         gmtload(lclptr);
  922.     settzname();
  923. }
  924.  
  925. void
  926. tzset P((void))
  927. {
  928.     register const char *    name;
  929.  
  930.     name = getenv("TZ");
  931.     if (name == NULL) {
  932.         tzsetwall();
  933.         return;
  934.     }
  935.  
  936.     if (lcl_is_set > 0  &&  strcmp(lcl_TZname, name) == 0)
  937.         return;
  938.     lcl_is_set = (strlen(name) < sizeof(lcl_TZname));
  939.     if (lcl_is_set)
  940.         (void) strcpy(lcl_TZname, name);
  941.  
  942. #ifdef ALL_STATE
  943.     if (lclptr == NULL) {
  944.         lclptr = (struct state *) malloc(sizeof *lclptr);
  945.         if (lclptr == NULL) {
  946.             settzname();    /* all we can do */
  947.             return;
  948.         }
  949.     }
  950. #endif /* defined ALL_STATE */
  951.     if (*name == '\0') {
  952.         /*
  953.         ** User wants it fast rather than right.
  954.         */
  955.         lclptr->leapcnt = 0;        /* so, we're off a little */
  956.         lclptr->timecnt = 0;
  957.         lclptr->ttis[0].tt_gmtoff = 0;
  958.         lclptr->ttis[0].tt_abbrind = 0;
  959.         (void) strcpy(lclptr->chars, gmt);
  960.     } else if (tzload(name, lclptr) != 0)
  961.         if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
  962.             (void) gmtload(lclptr);
  963.     settzname();
  964. }
  965.  
  966. /*
  967. ** The easy way to behave "as if no library function calls" localtime
  968. ** is to not call it--so we drop its guts into "localsub", which can be
  969. ** freely called.  (And no, the PANS doesn't require the above behavior--
  970. ** but it *is* desirable.)
  971. **
  972. ** The unused offset argument is for the benefit of mktime variants.
  973. */
  974.  
  975. /*ARGSUSED*/
  976. static void
  977. localsub(timep, offset, tmp)
  978. const time_t * const    timep;
  979. const long        offset;
  980. struct tm * const    tmp;
  981. {
  982.     register struct state *        sp;
  983.     register const struct ttinfo *    ttisp;
  984.     register int            i;
  985.     const time_t            t = *timep;
  986.  
  987.     sp = lclptr;
  988. #ifdef ALL_STATE
  989.     if (sp == NULL) {
  990.         gmtsub(timep, offset, tmp);
  991.         return;
  992.     }
  993. #endif /* defined ALL_STATE */
  994.     if (sp->timecnt == 0 || t < sp->ats[0]) {
  995.         i = 0;
  996.         while (sp->ttis[i].tt_isdst)
  997.             if (++i >= sp->typecnt) {
  998.                 i = 0;
  999.                 break;
  1000.             }
  1001.     } else {
  1002.         for (i = 1; i < sp->timecnt; ++i)
  1003.             if (t < sp->ats[i])
  1004.                 break;
  1005.         i = sp->types[i - 1];
  1006.     }
  1007.     ttisp = &sp->ttis[i];
  1008.     /*
  1009.     ** To get (wrong) behavior that's compatible with System V Release 2.0
  1010.     ** you'd replace the statement below with
  1011.     **    t += ttisp->tt_gmtoff;
  1012.     **    timesub(&t, 0L, sp, tmp);
  1013.     */
  1014.     timesub(&t, ttisp->tt_gmtoff, sp, tmp);
  1015.     tmp->tm_isdst = ttisp->tt_isdst;
  1016.     tzname[tmp->tm_isdst] = &sp->chars[ttisp->tt_abbrind];
  1017. #ifdef TM_ZONE
  1018.     tmp->TM_ZONE = &sp->chars[ttisp->tt_abbrind];
  1019. #endif /* defined TM_ZONE */
  1020. }
  1021.  
  1022. struct tm *
  1023. localtime(timep)
  1024. const time_t * const    timep;
  1025. {
  1026.     tzset();
  1027.     localsub(timep, 0L, &tm);
  1028.     return &tm;
  1029. }
  1030.  
  1031. /*
  1032. ** gmtsub is to gmtime as localsub is to localtime.
  1033. */
  1034.  
  1035. static void
  1036. gmtsub(timep, offset, tmp)
  1037. const time_t * const    timep;
  1038. const long        offset;
  1039. struct tm * const    tmp;
  1040. {
  1041.     if (!gmt_is_set) {
  1042.         gmt_is_set = TRUE;
  1043. #ifdef ALL_STATE
  1044.         gmtptr = (struct state *) malloc(sizeof *gmtptr);
  1045.         if (gmtptr != NULL)
  1046. #endif /* defined ALL_STATE */
  1047.             gmtload(gmtptr);
  1048.     }
  1049.     timesub(timep, offset, gmtptr, tmp);
  1050. #ifdef TM_ZONE
  1051.     /*
  1052.     ** Could get fancy here and deliver something such as
  1053.     ** "GMT+xxxx" or "GMT-xxxx" if offset is non-zero,
  1054.     ** but this is no time for a treasure hunt.
  1055.     */
  1056.     if (offset != 0)
  1057.         tmp->TM_ZONE = wildabbr;
  1058.     else {
  1059. #ifdef ALL_STATE
  1060.         if (gmtptr == NULL)
  1061.             tmp->TM_ZONE = gmt;
  1062.         else    tmp->TM_ZONE = gmtptr->chars;
  1063. #endif /* defined ALL_STATE */
  1064. #ifndef ALL_STATE
  1065.         tmp->TM_ZONE = gmtptr->chars;
  1066. #endif /* State Farm */
  1067.     }
  1068. #endif /* defined TM_ZONE */
  1069. }
  1070.  
  1071. struct tm *
  1072. gmtime(timep)
  1073. const time_t * const    timep;
  1074. {
  1075.     gmtsub(timep, 0L, &tm);
  1076.     return &tm;
  1077. }
  1078.  
  1079. #ifdef STD_INSPIRED
  1080.  
  1081. struct tm *
  1082. offtime(timep, offset)
  1083. const time_t * const    timep;
  1084. const long        offset;
  1085. {
  1086.     gmtsub(timep, offset, &tm);
  1087.     return &tm;
  1088. }
  1089.  
  1090. #endif /* defined STD_INSPIRED */
  1091.  
  1092. static void
  1093. timesub(timep, offset, sp, tmp)
  1094. const time_t * const            timep;
  1095. const long                offset;
  1096. register const struct state * const    sp;
  1097. register struct tm * const        tmp;
  1098. {
  1099.     register const struct lsinfo *    lp;
  1100.     register long            days;
  1101.     register long            rem;
  1102.     register int            y;
  1103.     register int            yleap;
  1104.     register const int *        ip;
  1105.     register long            corr;
  1106.     register int            hit;
  1107.     register int            i;
  1108.  
  1109.     corr = 0;
  1110.     hit = 0;
  1111. #ifdef ALL_STATE
  1112.     i = (sp == NULL) ? 0 : sp->leapcnt;
  1113. #endif /* defined ALL_STATE */
  1114. #ifndef ALL_STATE
  1115.     i = sp->leapcnt;
  1116. #endif /* State Farm */
  1117.     while (--i >= 0) {
  1118.         lp = &sp->lsis[i];
  1119.         if (*timep >= lp->ls_trans) {
  1120.             if (*timep == lp->ls_trans) {
  1121.                 hit = ((i == 0 && lp->ls_corr > 0) ||
  1122.                     lp->ls_corr > sp->lsis[i - 1].ls_corr);
  1123.                 if (hit)
  1124.                     while (i > 0 &&
  1125.                         sp->lsis[i].ls_trans ==
  1126.                         sp->lsis[i - 1].ls_trans + 1 &&
  1127.                         sp->lsis[i].ls_corr ==
  1128.                         sp->lsis[i - 1].ls_corr + 1) {
  1129.                             ++hit;
  1130.                             --i;
  1131.                     }
  1132.             }
  1133.             corr = lp->ls_corr;
  1134.             break;
  1135.         }
  1136.     }
  1137.     days = *timep / SECSPERDAY;
  1138.     rem = *timep % SECSPERDAY;
  1139. #ifdef mc68k
  1140.     if (*timep == 0x80000000) {
  1141.         /*
  1142.         ** A 3B1 muffs the division on the most negative number.
  1143.         */
  1144.         days = -24855;
  1145.         rem = -11648;
  1146.     }
  1147. #endif /* defined mc68k */
  1148.     rem += (offset - corr);
  1149.     while (rem < 0) {
  1150.         rem += SECSPERDAY;
  1151.         --days;
  1152.     }
  1153.     while (rem >= SECSPERDAY) {
  1154.         rem -= SECSPERDAY;
  1155.         ++days;
  1156.     }
  1157.     tmp->tm_hour = (int) (rem / SECSPERHOUR);
  1158.     rem = rem % SECSPERHOUR;
  1159.     tmp->tm_min = (int) (rem / SECSPERMIN);
  1160.     tmp->tm_sec = (int) (rem % SECSPERMIN);
  1161.     if (hit)
  1162.         /*
  1163.         ** A positive leap second requires a special
  1164.         ** representation.  This uses "... ??:59:60" et seq.
  1165.         */
  1166.         tmp->tm_sec += hit;
  1167.     tmp->tm_wday = (int) ((EPOCH_WDAY + days) % DAYSPERWEEK);
  1168.     if (tmp->tm_wday < 0)
  1169.         tmp->tm_wday += DAYSPERWEEK;
  1170.     y = EPOCH_YEAR;
  1171. #define LEAPS_THRU_END_OF(y)    ((y) / 4 - (y) / 100 + (y) / 400)
  1172.     while (days < 0 || days >= (long) year_lengths[yleap = isleap(y)]) {
  1173.         register int    newy;
  1174.  
  1175.         newy = y + days / DAYSPERNYEAR;
  1176.         if (days < 0)
  1177.             --newy;
  1178.         days -= (newy - y) * DAYSPERNYEAR +
  1179.             LEAPS_THRU_END_OF(newy - 1) -
  1180.             LEAPS_THRU_END_OF(y - 1);
  1181.         y = newy;
  1182.     }
  1183.     tmp->tm_year = y - TM_YEAR_BASE;
  1184.     tmp->tm_yday = (int) days;
  1185.     ip = mon_lengths[yleap];
  1186.     for (tmp->tm_mon = 0; days >= (long) ip[tmp->tm_mon]; ++(tmp->tm_mon))
  1187.         days = days - (long) ip[tmp->tm_mon];
  1188.     tmp->tm_mday = (int) (days + 1);
  1189.     tmp->tm_isdst = 0;
  1190. #ifdef TM_GMTOFF
  1191.     tmp->TM_GMTOFF = offset;
  1192. #endif /* defined TM_GMTOFF */
  1193. }
  1194.  
  1195. char *
  1196. ctime(timep)
  1197. const time_t * const    timep;
  1198. {
  1199. /*
  1200. ** Section 4.12.3.2 of X3.159-1989 requires that
  1201. **    The ctime funciton converts the calendar time pointed to by timer
  1202. **    to local time in the form of a string.  It is equivalent to
  1203. **        asctime(localtime(timer))
  1204. */
  1205.     return asctime(localtime(timep));
  1206. }
  1207.  
  1208. /*
  1209. ** Adapted from code provided by Robert Elz, who writes:
  1210. **    The "best" way to do mktime I think is based on an idea of Bob
  1211. **    Kridle's (so its said...) from a long time ago. (mtxinu!kridle now).
  1212. **    It does a binary search of the time_t space.  Since time_t's are
  1213. **    just 32 bits, its a max of 32 iterations (even at 64 bits it
  1214. **    would still be very reasonable).
  1215. */
  1216.  
  1217. #ifndef WRONG
  1218. #define WRONG    (-1)
  1219. #endif /* !defined WRONG */
  1220.  
  1221. /*
  1222. ** Simplified normalize logic courtesy Paul Eggert (eggert@twinsun.com).
  1223. */
  1224.  
  1225. static int
  1226. increment_overflow(number, delta)
  1227. int *    number;
  1228. int    delta;
  1229. {
  1230.     int    number0;
  1231.  
  1232.     number0 = *number;
  1233.     *number += delta;
  1234.     return (*number < number0) != (delta < 0);
  1235. }
  1236.  
  1237. static int
  1238. normalize_overflow(tensptr, unitsptr, base)
  1239. int * const    tensptr;
  1240. int * const    unitsptr;
  1241. const int    base;
  1242. {
  1243.     register int    tensdelta;
  1244.  
  1245.     tensdelta = (*unitsptr >= 0) ?
  1246.         (*unitsptr / base) :
  1247.         (-1 - (-1 - *unitsptr) / base);
  1248.     *unitsptr -= tensdelta * base;
  1249.     return increment_overflow(tensptr, tensdelta);
  1250. }
  1251.  
  1252. static int
  1253. tmcomp(atmp, btmp)
  1254. register const struct tm * const atmp;
  1255. register const struct tm * const btmp;
  1256. {
  1257.     register int    result;
  1258.  
  1259.     if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
  1260.         (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
  1261.         (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
  1262.         (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
  1263.         (result = (atmp->tm_min - btmp->tm_min)) == 0)
  1264.             result = atmp->tm_sec - btmp->tm_sec;
  1265.     return result;
  1266. }
  1267.  
  1268. static time_t
  1269. time2(tmp, funcp, offset, okayp)
  1270. struct tm * const    tmp;
  1271. void (* const        funcp) P((const time_t*, long, struct tm*));
  1272. const long        offset;
  1273. int * const        okayp;
  1274. {
  1275.     register const struct state *    sp;
  1276.     register int            dir;
  1277.     register int            bits;
  1278.     register int            i, j ;
  1279.     register int            saved_seconds;
  1280.     time_t                newt;
  1281.     time_t                t;
  1282.     struct tm            yourtm, mytm;
  1283.  
  1284.     *okayp = FALSE;
  1285.     yourtm = *tmp;
  1286.     if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR))
  1287.         return WRONG;
  1288.     if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY))
  1289.         return WRONG;
  1290.     if (normalize_overflow(&yourtm.tm_year, &yourtm.tm_mon, MONSPERYEAR))
  1291.         return WRONG;
  1292.     /*
  1293.     ** Turn yourtm.tm_year into an actual year number for now.
  1294.     ** It is converted back to an offset from TM_YEAR_BASE later.
  1295.     */
  1296.     if (increment_overflow(&yourtm.tm_year, TM_YEAR_BASE))
  1297.         return WRONG;
  1298.     while (yourtm.tm_mday <= 0) {
  1299.         if (increment_overflow(&yourtm.tm_year, -1))
  1300.             return WRONG;
  1301.         yourtm.tm_mday += year_lengths[isleap(yourtm.tm_year)];
  1302.     }
  1303.     while (yourtm.tm_mday > DAYSPERLYEAR) {
  1304.         yourtm.tm_mday -= year_lengths[isleap(yourtm.tm_year)];
  1305.         if (increment_overflow(&yourtm.tm_year, 1))
  1306.             return WRONG;
  1307.     }
  1308.     for ( ; ; ) {
  1309.         i = mon_lengths[isleap(yourtm.tm_year)][yourtm.tm_mon];
  1310.         if (yourtm.tm_mday <= i)
  1311.             break;
  1312.         yourtm.tm_mday -= i;
  1313.         if (++yourtm.tm_mon >= MONSPERYEAR) {
  1314.             yourtm.tm_mon = 0;
  1315.             if (increment_overflow(&yourtm.tm_year, 1))
  1316.                 return WRONG;
  1317.         }
  1318.     }
  1319.     if (increment_overflow(&yourtm.tm_year, -TM_YEAR_BASE))
  1320.         return WRONG;
  1321.     if (yourtm.tm_year + TM_YEAR_BASE < EPOCH_YEAR) {
  1322.         /*
  1323.         ** We can't set tm_sec to 0, because that might push the
  1324.         ** time below the minimum representable time.
  1325.         ** Set tm_sec to 59 instead.
  1326.         ** This assumes that the minimum representable time is
  1327.         ** not in the same minute that a leap second was deleted from,
  1328.         ** which is a safer assumption than using 58 would be.
  1329.         */
  1330.         if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN))
  1331.             return WRONG;
  1332.         saved_seconds = yourtm.tm_sec;
  1333.         yourtm.tm_sec = SECSPERMIN - 1;
  1334.     } else {
  1335.         saved_seconds = yourtm.tm_sec;
  1336.         yourtm.tm_sec = 0;
  1337.     }
  1338.     /*
  1339.     ** Calculate the number of magnitude bits in a time_t
  1340.     ** (this works regardless of whether time_t is
  1341.     ** signed or unsigned, though lint complains if unsigned).
  1342.     */
  1343.     for (bits = 0, t = 1; t > 0; ++bits, t <<= 1)
  1344.         continue;
  1345.     /*
  1346.     ** If time_t is signed, then 0 is the median value,
  1347.     ** if time_t is unsigned, then 1 << bits is median.
  1348.     */
  1349.     t = (t < 0) ? 0 : ((time_t) 1 << bits);
  1350.     for ( ; ; ) {
  1351.         (*funcp)(&t, offset, &mytm);
  1352.         dir = tmcomp(&mytm, &yourtm);
  1353.         if (dir != 0) {
  1354.             if (bits-- < 0)
  1355.                 return WRONG;
  1356.             if (bits < 0)
  1357.                 --t;
  1358.             else if (dir > 0)
  1359.                 t -= (time_t) 1 << bits;
  1360.             else    t += (time_t) 1 << bits;
  1361.             continue;
  1362.         }
  1363.         if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst)
  1364.             break;
  1365.         /*
  1366.         ** Right time, wrong type.
  1367.         ** Hunt for right time, right type.
  1368.         ** It's okay to guess wrong since the guess
  1369.         ** gets checked.
  1370.         */
  1371.         /*
  1372.         ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
  1373.         */
  1374.         sp = (const struct state *)
  1375.             (((void *) funcp == (void *) localsub) ?
  1376.             lclptr : gmtptr);
  1377. #ifdef ALL_STATE
  1378.         if (sp == NULL)
  1379.             return WRONG;
  1380. #endif /* defined ALL_STATE */
  1381.         for (i = sp->typecnt - 1; i >= 0; --i) {
  1382.             if (sp->ttis[i].tt_isdst != yourtm.tm_isdst)
  1383.                 continue;
  1384.             for (j = sp->typecnt - 1; j >= 0; --j) {
  1385.                 if (sp->ttis[j].tt_isdst == yourtm.tm_isdst)
  1386.                     continue;
  1387.                 newt = t + sp->ttis[j].tt_gmtoff -
  1388.                     sp->ttis[i].tt_gmtoff;
  1389.                 (*funcp)(&newt, offset, &mytm);
  1390.                 if (tmcomp(&mytm, &yourtm) != 0)
  1391.                     continue;
  1392.                 if (mytm.tm_isdst != yourtm.tm_isdst)
  1393.                     continue;
  1394.                 /*
  1395.                 ** We have a match.
  1396.                 */
  1397.                 t = newt;
  1398.                 goto label;
  1399.             }
  1400.         }
  1401.         return WRONG;
  1402.     }
  1403. label:
  1404.     newt = t + saved_seconds;
  1405.     if ((newt < t) != (saved_seconds < 0))
  1406.         return WRONG;
  1407.     t = newt;
  1408.     (*funcp)(&t, offset, tmp);
  1409.     *okayp = TRUE;
  1410.     return t;
  1411. }
  1412.  
  1413. static time_t
  1414. time1(tmp, funcp, offset)
  1415. struct tm * const    tmp;
  1416. void (* const        funcp) P((const time_t *, long, struct tm *));
  1417. const long        offset;
  1418. {
  1419.     register time_t            t;
  1420.     register const struct state *    sp;
  1421.     register int            samei, otheri;
  1422.     int                okay;
  1423.  
  1424.     if (tmp->tm_isdst > 1)
  1425.         tmp->tm_isdst = 1;
  1426.     t = time2(tmp, funcp, offset, &okay);
  1427. #ifdef PCTS
  1428.     /*
  1429.     ** PCTS code courtesy Grant Sullivan (grant@osf.org).
  1430.     */
  1431.     if (okay)
  1432.         return t;
  1433.     if (tmp->tm_isdst < 0)
  1434.         tmp->tm_isdst = 0;    /* reset to std and try again */
  1435. #endif /* defined PCTS */
  1436. #ifndef PCTS
  1437.     if (okay || tmp->tm_isdst < 0)
  1438.         return t;
  1439. #endif /* !defined PCTS */
  1440.     /*
  1441.     ** We're supposed to assume that somebody took a time of one type
  1442.     ** and did some math on it that yielded a "struct tm" that's bad.
  1443.     ** We try to divine the type they started from and adjust to the
  1444.     ** type they need.
  1445.     */
  1446.     /*
  1447.     ** The (void *) casts are the benefit of SunOS 3.3 on Sun 2's.
  1448.     */
  1449.     sp = (const struct state *) (((void *) funcp == (void *) localsub) ?
  1450.         lclptr : gmtptr);
  1451. #ifdef ALL_STATE
  1452.     if (sp == NULL)
  1453.         return WRONG;
  1454. #endif /* defined ALL_STATE */
  1455.     for (samei = sp->typecnt - 1; samei >= 0; --samei) {
  1456.         if (sp->ttis[samei].tt_isdst != tmp->tm_isdst)
  1457.             continue;
  1458.         for (otheri = sp->typecnt - 1; otheri >= 0; --otheri) {
  1459.             if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst)
  1460.                 continue;
  1461.             tmp->tm_sec += sp->ttis[otheri].tt_gmtoff -
  1462.                     sp->ttis[samei].tt_gmtoff;
  1463.             tmp->tm_isdst = !tmp->tm_isdst;
  1464.             t = time2(tmp, funcp, offset, &okay);
  1465.             if (okay)
  1466.                 return t;
  1467.             tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff -
  1468.                     sp->ttis[samei].tt_gmtoff;
  1469.             tmp->tm_isdst = !tmp->tm_isdst;
  1470.         }
  1471.     }
  1472.     return WRONG;
  1473. }
  1474.  
  1475. time_t
  1476. mktime(tmp)
  1477. struct tm * const    tmp;
  1478. {
  1479.     tzset();
  1480.     return time1(tmp, localsub, 0L);
  1481. }
  1482.  
  1483. #ifdef STD_INSPIRED
  1484.  
  1485. time_t
  1486. timelocal(tmp)
  1487. struct tm * const    tmp;
  1488. {
  1489.     tmp->tm_isdst = -1;    /* in case it wasn't initialized */
  1490.     return mktime(tmp);
  1491. }
  1492.  
  1493. time_t
  1494. timegm(tmp)
  1495. struct tm * const    tmp;
  1496. {
  1497.     tmp->tm_isdst = 0;
  1498.     return time1(tmp, gmtsub, 0L);
  1499. }
  1500.  
  1501. time_t
  1502. timeoff(tmp, offset)
  1503. struct tm * const    tmp;
  1504. const long        offset;
  1505. {
  1506.     tmp->tm_isdst = 0;
  1507.     return time1(tmp, gmtsub, offset);
  1508. }
  1509.  
  1510. #endif /* defined STD_INSPIRED */
  1511.  
  1512. #ifdef CMUCS
  1513.  
  1514. /*
  1515. ** The following is supplied for compatibility with
  1516. ** previous versions of the CMUCS runtime library.
  1517. */
  1518.  
  1519. long
  1520. gtime(tmp)
  1521. struct tm * const    tmp;
  1522. {
  1523.     const time_t    t = mktime(tmp);
  1524.  
  1525.     if (t == WRONG)
  1526.         return -1;
  1527.     return t;
  1528. }
  1529.  
  1530. #endif /* defined CMUCS */
  1531.  
  1532. /*
  1533. ** XXX--is the below the right way to conditionalize??
  1534. */
  1535.  
  1536. #ifdef STD_INSPIRED
  1537.  
  1538. /*
  1539. ** IEEE Std 1003.1-1988 (POSIX) legislates that 536457599
  1540. ** shall correspond to "Wed Dec 31 23:59:59 GMT 1986", which
  1541. ** is not the case if we are accounting for leap seconds.
  1542. ** So, we provide the following conversion routines for use
  1543. ** when exchanging timestamps with POSIX conforming systems.
  1544. */
  1545.  
  1546. static long
  1547. leapcorr(timep)
  1548. time_t *    timep;
  1549. {
  1550.     register struct state *        sp;
  1551.     register struct lsinfo *    lp;
  1552.     register int            i;
  1553.  
  1554.     sp = lclptr;
  1555.     i = sp->leapcnt;
  1556.     while (--i >= 0) {
  1557.         lp = &sp->lsis[i];
  1558.         if (*timep >= lp->ls_trans)
  1559.             return lp->ls_corr;
  1560.     }
  1561.     return 0;
  1562. }
  1563.  
  1564. time_t
  1565. time2posix(t)
  1566. time_t    t;
  1567. {
  1568.     tzset();
  1569.     return t - leapcorr(&t);
  1570. }
  1571.  
  1572. time_t
  1573. posix2time(t)
  1574. time_t    t;
  1575. {
  1576.     time_t    x;
  1577.     time_t    y;
  1578.  
  1579.     tzset();
  1580.     /*
  1581.     ** For a positive leap second hit, the result
  1582.     ** is not unique.  For a negative leap second
  1583.     ** hit, the corresponding time doesn't exist,
  1584.     ** so we return an adjacent second.
  1585.     */
  1586.     x = t + leapcorr(&t);
  1587.     y = x - leapcorr(&x);
  1588.     if (y < t) {
  1589.         do {
  1590.             x++;
  1591.             y = x - leapcorr(&x);
  1592.         } while (y < t);
  1593.         if (t != y)
  1594.             return x - 1;
  1595.     } else if (y > t) {
  1596.         do {
  1597.             --x;
  1598.             y = x - leapcorr(&x);
  1599.         } while (y > t);
  1600.         if (t != y)
  1601.             return x + 1;
  1602.     }
  1603.     return x;
  1604. }
  1605.  
  1606. #endif /* defined STD_INSPIRED */
  1607.